using System.Windows.Forms;
using NUnit.Framework;
using Rhino.Mocks;
using ShadeTree.Binding.Elements;

namespace ShadeTree.Binding.Tests.Elements
{
    [TestFixture]
    public class BoundElementEventsAndDirtyTester
    {
        [Test]
        public void DoNotNotifyScreenBinderIfDirtyIsFalse()
        {
            var target = new BoundElementTarget("Darth Vader");
            Accessor property = ReflectionHelper.GetAccessor<BoundElementTarget>(x => x.Name);
            var label = new Label();

            var element = new StubbedBoundElement(property, label);
            element.Bind(target);
            element.IsDirty().ShouldBeFalse();

            var mocks = new MockRepository();
            var binder = mocks.StrictMock<IScreenBinder>();

            using (mocks.Record())
            {
                Expect.Call(binder.IsLatched).Return(false);
                // nothing, not one single thing should happen here because the element is NOT dirty
            }

            using (mocks.Playback())
            {
                element.Binder = binder;
                element.FireChangedEvent();
            }
        }

        [Test]
        public void IsDirty_check()
        {
            var target = new BoundElementTarget("Darth Vader");
            Accessor property = ReflectionHelper.GetAccessor<BoundElementTarget>(x => x.Name);
            var label = new Label();

            var element = new StubbedBoundElement(property, label);
            element.Bind(target);

            element.IsDirty().ShouldBeFalse();

            target.Name = "Luke Skywalker";
            element.IsDirty().ShouldBeTrue();
        }


        [Test]
        public void NotifyScreenBinderOnChangeIfDirtyIsTrue()
        {
            var target = new BoundElementTarget("Darth Vader");
            Accessor property = ReflectionHelper.GetAccessor<BoundElementTarget>(x => x.Name);
            var label = new Label();

            var element = new StubbedBoundElement(property, label);
            element.Bind(target);

            label.Text = "Han Solo";

            var mocks = new MockRepository();
            var binder = mocks.StrictMock<IScreenBinder>();


            using (mocks.Record())
            {
                Expect.Call(binder.IsLatched).Return(false);
                binder.Validate(element);

                Expect.Call(binder.OnChange).Return(() => { });
            }

            using (mocks.Playback())
            {
                element.Binder = binder;
                element.FireChangedEvent();
            }
        }
    }

    public class BoundElementTarget
    {
        public BoundElementTarget(string name)
        {
            Name = name;
        }

        public string Name { get; set; }
    }

    public class StubbedBoundElement : BoundScreenElement<Label, string>
    {
        public StubbedBoundElement(Accessor property, Label control) : base(property, control)
        {
        }

        public void FireChangedEvent()
        {
            elementValueChanged();
        }

        protected override string getValueFromControl()
        {
            return BoundControl.Text;
        }

        protected override void resetControl(string originalValue)
        {
            BoundControl.Text = originalValue;
        }

        protected override void tearDown()
        {
        }
    }
}